using System;
using System.Collections.Generic;
using System.Linq;

namespace OTE.Web.Infrastructure.TabMenu
{
    public class MenuBuilder
    {
        private readonly List<MenuModel> _menuModel = new List<MenuModel>();

        public string ActionName { get; set; }

        public string ControllerName { get; set; }

        public static MenuBuilder GetInstance(string controllerName = "")
        {
            var builder = new MenuBuilder { ControllerName = controllerName };
            return builder;
        }

        public MenuBuilder Add(MenuModel menuModel)
        {
            _menuModel.Add(menuModel);
            return this;
        }

        public MenuBuilder Add(string menuText, string actionName, Func<MenuModel, MenuRouteValue> getObject = null)
        {
            Add(new MenuModelItem(menuText), actionName, getObject);
            return this;
        }

        public MenuBuilder Add(MenuModelItem menuModelItem, string actionName, Func<MenuModel, MenuRouteValue> getObject = null)
        {
            var menuModel = new MenuModel
            {
                MenuValue = menuModelItem.Key,
                MenuText = menuModelItem.Text,
                MenuAction = actionName,
                MenuType = menuModelItem.Type,
                MenuController = ControllerName
            };

            if (getObject != null)
                menuModel.MenuRouteValues = getObject(menuModel);

            _menuModel.Add(menuModel);
            return this;
        }

        public MenuBuilder Add(MenuModelItem menuModelItem, string controllerName, string actionName, Func<MenuModel, MenuRouteValue> getObject = null)
        {
            var menuModel = new MenuModel
            {
                MenuValue = menuModelItem.Key,
                MenuText = menuModelItem.Text,
                MenuAction = actionName,
                MenuType = menuModelItem.Type,
                MenuController = controllerName
            };

            if (getObject != null)
            {
                menuModel.MenuRouteValues = getObject(menuModel);
            }

            _menuModel.Add(menuModel);
            return this;
        }

        public MenuBuilder AddRange(List<string> menuTexts, string actionName, Func<MenuModel, MenuRouteValue> getObject = null)
        {
            AddRange(menuTexts.Select(e => new MenuModelItem(e)).ToList(), actionName, getObject);
            return this;
        }

        public MenuBuilder AddRange(List<MenuModelItem> menuModelItems, string actionName, Func<MenuModel, MenuRouteValue> getObject = null)
        {
            foreach (var item in menuModelItems)
            {
                Add(item, actionName, getObject);
            }

            return this;
        }

        public MenuBuilder Selected(Predicate<MenuModel> predicate)
        {
            Selected(_menuModel, predicate);
            return this;
        }

        public static void Selected(List<MenuModel> menuModels, Predicate<MenuModel> predicate)
        {
            foreach (var menuModel in menuModels)
            {
                menuModel.IsSelected = false;
                menuModel.IsSelected = predicate(menuModel);
            }
        }

        public List<MenuModel> ToList()
        {
            return _menuModel;
        }
    }

    public class MenuModel
    {
        public object MenuValue { get; set; }

        public string MenuText { get; set; }

        public string MenuAction { get; set; }

        public string MenuController { get; set; }

        public MenuRouteValue MenuRouteValues { get; set; }

        public string MenuType { get; set; }

        public bool IsSelected { get; set; }
    }

    public class MenuRouteValue
    {
        public int ID { get; set; }

        public string Localecode { get; set; }

        public int ParentId { get; set; }

        public object GetObject()
        {
            if (Localecode != null)
                return new { id = ID, localecode = Localecode };
            if (ParentId > 0)
                return new { id = ID, parentId = ParentId };
            return new { id = ID };
        }
    }

    public class MenuModelItem
    {
        public MenuModelItem()
        {
        }

        public MenuModelItem(string text, object key = null, string type = "")
        {
            Text = text;
            Key = key ?? text;
            Type = type;
        }

        public object Key { get; set; }

        public string Text { get; set; }

        public string Type { get; set; }
    }
}